import cloneDeep from 'lodash/cloneDeep'
import { login, logout, getInfo } from '@/api/user'
import { getToken, setToken, removeToken } from '@/utils/auth'
import router, {
  resetRouter,
  asyncRoutes,
  constantRoutes,
  anyRoute
} from '@/router'

function filterRoutes(routes, asyncRoutes) {
  const permissionRoutes = []

  asyncRoutes.forEach((route) => {
    // 判断route在不在用户权限值routes中？
    if (routes.indexOf(route.name) !== -1) {
      // 在
      // 还需要对子路由进行判断
      if (route.children) {
        // 修改了原来asyncRoutes中的某个route的children属性
        route.children = filterRoutes(routes, route.children)
      }
      // 添加到用户权限路由表
      permissionRoutes.push(route)
    }
  })

  return permissionRoutes
}

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',
    routes: [], // 路由权限值
    buttons: [] // 按钮权限值
  }
}

const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  // SET_NAME: (state, name) => {
  //   state.name = name
  // },
  // SET_AVATAR: (state, avatar) => {
  //   state.avatar = avatar
  // },
  // SET_PERMISSION(state, permission) {
  //   state.routes = permission.routes
  //   state.buttons = permission.buttons
  // }
  SET_USER_INFO(state, user) {
    state.name = user.name
    state.avatar = user.avatar
    state.routes = user.routes
    state.buttons = user.buttons
  }
}

const actions = {
  // 用户登陆时触发的action函数
  login({ commit }, userInfo) {
    // 获取用户名和密码
    const { username, password } = userInfo
    // 返回一个promise对象，所以外面使用action函数时，返回值可以使用then/catch
    return new Promise((resolve, reject) => {
      // 调用login函数 -> 接口函数
      login({ username: username.trim(), password: password })
        .then((response) => {
          const { token } = response.data
          // 将token存储在vuex中
          commit('SET_TOKEN', token)
          // 将token持久化存储 - cookie
          setToken(token)
          // 将promise对象的状态改成成功状态
          resolve()
        })
        .catch((error) => {
          reject(error)
        })
    })
  },

  // 获取用户信息的action函数
  getInfo({ commit }) {
    return new Promise((resolve, reject) => {
      // 获取用户信息，需要在请求头携带token参数，在哪里做？
      // 正常情况下：token是除登陆以外其他所有请求都需要在请求头携带的（当我们项目不是，为了简单）
      // 意思是：基本所有请求都需要携带token，在哪里做更方便？封装axios函数中请求拦截器设置token
      getInfo()
        .then((response) => {
          const { data } = response

          if (!data) {
            reject('验证失败，请重新登陆')
          }

          // 将用户数据存储到vuex中
          // const { name, avatar, routes, buttons } = data
          // commit('SET_NAME', name)
          // commit('SET_AVATAR', avatar)
          // commit('SET_PERMISSION', { routes, buttons })

          // 根据用户数据 routes 路由权限值，遍历 asyncRoutes 判断异步路由表中的路由在不在用户的路由权限值中
          // 如果在的话，路由就保留，不再的话就要过滤，这样就能生成一个用户拥有权限访问的路由表
          const permissionRoutes = filterRoutes(
            data.routes,
            cloneDeep(asyncRoutes)
          )
          // console.log(permissionRoutes, data.routes)
          // 想办法让这个用户拥有权限访问的路由表追加到前端路由，让其生效，用户就能访问其他路由了～
          router.addRoutes(permissionRoutes) // 动态添加多个路由

          // 重新赋值routes，不再是之前的路由权限值
          // 而是拥有访问权限的路由表
          data.routes = [...constantRoutes, ...permissionRoutes, anyRoute]
          // 将用户数据存储到vuex中
          commit('SET_USER_INFO', data)

          resolve()
        })
        .catch((error) => {
          reject(error)
        })
    })
  },

  // user logout
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token)
        .then(() => {
          removeToken() // must remove  token  first
          resetRouter()
          commit('RESET_STATE')
          resolve()
        })
        .catch((error) => {
          reject(error)
        })
    })
  },

  // 重制token，将存储的token给删除
  resetToken({ commit }) {
    return new Promise((resolve) => {
      removeToken() // 删除cookie中token
      commit('RESET_STATE') // 重置所有用户数据为空
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
